/*
 * CommunicationAdpt.cpp
 *
 */

#include "CommunicationAdpt.h"
#include "../logger/logger.h"
#include "../channel_common/agent_address_service/AgentAddressService.h"
#include "../capa_servicios_distribuidos/QueueLauncher.h"

namespace middleware {

const std::string middleware::CommunicationAdpt::MUTEX_PATH = "/tmp/adpt";

const Uid CommunicationAdpt::UIDRequest = "adptRequest";
const Uid CommunicationAdpt::UIDVendedorReply = "adptVendedorReply";
const Uid CommunicationAdpt::UIDRobot16Reply = "adptRobot16Reply";

CommunicationAdpt::CommunicationAdpt(std::string hostName):
		m_Mutex(ipc::Semaphore::get(MUTEX_PATH+hostName,MUTEX_KEY)),
		m_RequestQueue(ipc::MessageQueue<AdptRequestStruct>::
		get(IPCUids::getFile(UIDRequest)+hostName,IPCUids::getKey(UIDRequest))),
		m_VendedorReplyQueue(ipc::MessageQueue<AdptReplyVendedorStruct>::
		get(IPCUids::getFile(UIDVendedorReply)+hostName,IPCUids::getKey(UIDVendedorReply))),
		m_Robot16ReplyQueue(ipc::MessageQueue<AdptReplyRobot16Struct>::
		get(IPCUids::getFile(UIDRobot16Reply)+hostName,IPCUids::getKey(UIDRobot16Reply)))
{
	m_mTypeReq = channel::AgentAddressService::resolve(UIDRequest);
	m_mtypeRobot16Req = channel::AgentAddressService::resolve("robot16_rep");
}

CommunicationAdpt::~CommunicationAdpt()
{
}

bool CommunicationAdpt::reservarProductos(
		OrdenCompraHeader ordenCompraId,
		const ProductoCantidadList& productos,
		ProductoCantidadList& productosReservados,
		ProductoCantidadMap& cantidadesMinimas)
{
	bool retVal=false;
	AdptRequestStruct request;
	AdptReplyVendedorStruct reply;
	ProductoCantidadList::const_iterator it;
	ProductoCantidadMap::const_iterator itMap;

	request.ordenCompra = ordenCompraId;

	m_Mutex.wait();

	//Voy enviando todos los productos dentro del pedido
	for(it=productos.begin();it!=productos.end();it++)
	{
		request.requestType = RESERVAR;
		request.productosCantidades = *it;

		itMap=cantidadesMinimas.find(request.productosCantidades.tipo);

		if(itMap !=cantidadesMinimas.end())
		{
			request.cantidadMinima = cantidadesMinimas[request.productosCantidades.tipo];
		}
		else
		{
			CLogger::log("No se paso la cantidad minima de productos a fabricar, usando cantidad por default", LogLevelEnum::WARN);
			request.cantidadMinima =5;
		}
		m_RequestQueue.put(m_mTypeReq,request);
	}

	//Envio un fin de pedido.
	request.requestType = FIN_RESERVA;
	m_RequestQueue.put(m_mTypeReq,request);

	do{
		reply = m_VendedorReplyQueue.get(1212);

//		reply = m_VendedorReplyQueue.get(ordenCompraId.vendedorId);

		productosReservados.push_back(reply.productosCantidades);

	}while(reply.status != FIN_RESPUESTA_RESERVA && reply.status != NO_HAY_ESPACIO);

	m_Mutex.signal();

	if(reply.status == FIN_RESPUESTA_RESERVA)
		retVal =true;

	return retVal;
}

void CommunicationAdpt::getAdptRequest(AdptRequestType& requestType,
											ProductoCantidad& productos,
											OrdenCompraHeader &ordenCompra,
											Producto &producto,
											int &cantMinima)
{
	AdptRequestStruct request;

	request = m_RequestQueue.get(m_mTypeReq);

	productos = request.productosCantidades;
	requestType = request.requestType;
	ordenCompra = request.ordenCompra;
	cantMinima = request.cantidadMinima;

	producto = request.producto;
}

void CommunicationAdpt::responderVendedor(AdptReplyStatus replyType,
							int vendedorId,ProductoCantidad prodCantidad)
{
	AdptReplyVendedorStruct reply;

	reply.status= replyType;
	reply.productosCantidades = prodCantidad;

	vendedorId = 1212;

	m_VendedorReplyQueue.put(vendedorId,reply);
}

void CommunicationAdpt::insertarProducto(Producto& producto)
{
	AdptRequestStruct request;

	request.producto=producto;
	request.requestType = CommunicationAdpt::INSERTAR;

	m_Mutex.wait();
	m_RequestQueue.put(m_mTypeReq,request);
	m_Mutex.signal();
}

void CommunicationAdpt::retirarProducto(TipoProducto tipoProducto,
		OrdenCompraHeader& ordenCompra, Producto& producto)
{
//	//TODO implementar!!
//	producto.tipo = tipoProducto;
//	producto.estado =PRODUCTO_TERMINADO;
//	producto.productoId = 4444;

	AdptRequestStruct request;
	AdptReplyRobot16Struct reply;

	request.requestType = RETIRAR;
	request.ordenCompra=ordenCompra;
	request.productosCantidades.tipo=tipoProducto;
	request.productosCantidades.cantidad=1;

	m_Mutex.wait();
	m_RequestQueue.put(m_mTypeReq,request);
	reply = m_Robot16ReplyQueue.get(m_mtypeRobot16Req);
	m_Mutex.signal();

	producto = reply.producto;
}

void CommunicationAdpt::entregarProducto(Producto &producto)
{
	AdptReplyRobot16Struct reply;
	reply.producto = producto;
	m_Robot16ReplyQueue.put(m_mtypeRobot16Req,reply);
}

void CommunicationAdpt::create(AdptCommunicationType type,std::string hostName)
{
	ipc::Semaphore::create(MUTEX_PATH+hostName,MUTEX_KEY,1).initialize(1);

	int mtypeAdptReq = channel::AgentAddressService::registerName(UIDRequest);
	int mtypeRobot16Req = channel::AgentAddressService::registerName("robot16_rep");

	servicios_distribuidos::QueueLauncher::createDistributedQueueByUid
		<AdptRequestStruct>(UIDRequest,hostName,
		(type == ADPT_HOST) ? servicios_distribuidos::QUEUE_RECV : servicios_distribuidos::QUEUE_SEND,mtypeAdptReq);

	//TODO launch dinamico
	servicios_distribuidos::QueueLauncher::createDistributedQueueByUid
		<AdptReplyVendedorStruct>(UIDVendedorReply,hostName,
		(type==VENDEDOR)?servicios_distribuidos::QUEUE_RECV: servicios_distribuidos::QUEUE_SEND ,1212);

	servicios_distribuidos::QueueLauncher::createDistributedQueueByUid
		<AdptReplyRobot16Struct>(UIDRobot16Reply,hostName,
		(type==ROBOT_16)? servicios_distribuidos::QUEUE_RECV: servicios_distribuidos::QUEUE_SEND ,mtypeRobot16Req);
}

void CommunicationAdpt::destroy(AdptCommunicationType type,std::string hostName)
{
	ipc::Semaphore::destroy(MUTEX_PATH+hostName,MUTEX_KEY);
	ipc::MessageQueue<AdptRequestStruct>::destroy(IPCUids::getFile(UIDRequest)+hostName,IPCUids::getKey(UIDRequest));
	ipc::MessageQueue<AdptReplyVendedorStruct>::destroy(IPCUids::getFile(UIDVendedorReply)+hostName,IPCUids::getKey(UIDVendedorReply));
	ipc::MessageQueue<AdptReplyRobot16Struct>::destroy(IPCUids::getFile(UIDRobot16Reply)+hostName,IPCUids::getKey(UIDRobot16Reply));
}

} /* namespace middleware */

